#include <iostream>
#include <string.h>
#include <fstream>
/**
 *********************** 三步走 ********************************
 * 1. 从文件读取源代码
 * 2. 进行词法分析
 * 3. 将结果存入文件中
*/

using namespace std;

#define MAX_LENGTH 1000	// 定义源代码最大长度
#define MAX_ID 32	// 标示符最大长度
#define MAX_LINE 100;

#define $READ 1
#define $WRITE 2
#define $ASSIGN 3
#define $BEGIN 4
#define $END 5
#define $TYPE_INT 6	// INT 数据类型
#define $ID 7
#define $INT 8	// 常数
#define $LPAR 9	// (
#define $RPAR 10	// ）
#define $PLUS 11 // +
#define $SUB 12	// -
#define $COMMA 13 // 注释符号 --
#define $SEMICOLON 14 // ;


char strToken[MAX_LENGTH] = {0};	// 声明全局字符数组，用来存储源代码，并将它初始化

char ch;	// 声明临时变量

struct resultFormat{	// 结果保存在一个二元组中
	int type;
	char attr[MAX_ID];
};

struct resultFormat results[MAX_LENGTH];

bool readSourceCode();	// 读取源代码

bool saveToFile(int nums);	// 将结果保存在文件中

int wordsParse();	// 词法分析
bool isLetter(char c);	// 判断c是不是字母
bool isDigit(char c);	// 判判c是不是数字
void concat(char str[], char c);	// 将c连接到str后
int reserve(char str[]);	// 判断当前字符串是什么类型

int main()
{
	int nums = 0;
	readSourceCode();
	nums = wordsParse();
	saveToFile(nums);
	cout<<"词法分析器任务结束，祝您使用愉快！"<<endl;
	return 0;
}

bool readSourceCode(){	// 读取源代码
	string line;
	int i;
	ifstream iFile;
	cout<<"正在打开文件"<<endl;
	iFile.open("./aaa.m");
	if(!iFile.is_open()){
		iFile.close();
		cout<<"打开文件失败"<<endl;
		return false;
	}
	cout<<"打开文件成功！"<<endl;
	cout<<"正在读取文件"<<endl;
	while(getline(iFile, line)){
		cout<<line<<"    正在被读入...";
		int j=0;
		ch = line.at(j);
		for(int j = 0; j<line.length(); j++){
			ch = line.at(j);
			strToken[i++] = ch;
		}
		strToken[i++] = ' ';
		cout<<"  完成！"<<endl;
	}
	iFile.close();
	
	cout<<"读入完毕："<<strToken<<endl;
	return true;
}

bool saveToFile(int nums){
	cout<<"正在准备写入文件"<<endl;
	ofstream oFile;
	cout<<"正在创建输出文件:./output.word"<<endl;
	oFile.open("./output.word");
	if(!oFile.is_open()){
		cout<<"打开文件失败"<<endl;
		oFile.close();
		return false;
	}
	cout<<"正在写入文件"<<endl;
	for(int i = 0;i<nums;i++){
		cout<<"正在写入第"<<i+1<<"行...";
		oFile<<results[i].type<<"\t"<<results[i].attr<<endl;
		cout<<"完成!"<<endl;
	}
	cout<<"写入文件成功"<<endl;
	oFile.close();
	return true;
}

int wordsParse(){
	int n = strlen(strToken);
	int i = 0, j = -1;
	ch = strToken[i];
	cout<<"正在进行词法分析"<<endl;
	while(ch != '\0'){
		char temp[MAX_ID] = {0};
		if(isLetter(ch)){
			while(isLetter(ch) || isDigit(ch)){
				concat(temp, ch);
				ch = strToken[++i];
			}
			i--;
			ch = ' ';
			int code = reserve(temp);
			results[++j].type = code;
			strcpy(results[j].attr, temp);
		}else if(ch == ';'){
			results[++j].type = $SEMICOLON;
			strcpy(results[j].attr, &ch);
		}else if(ch == '('){
			results[++j].type = $LPAR;
			strcpy(results[j].attr, &ch);
		}else if(ch == ')'){
			results[++j].type = $RPAR;
			strcpy(results[j].attr, &ch);
		}else if(ch == ':'){
			ch = strToken[++i];
			if(ch == '='){
				results[++j].type = $ASSIGN;
				strcpy(results[j].attr, ":=");
			}else{
				cout<<endl<<"ERROR:1"<<endl;
			}
		}else if(ch == '+'){
			results[++j].type = $PLUS;
			strcpy(results[j].attr, &ch);
		}else if(ch == ' '){
		}else if(isDigit(ch)){
			while(isDigit(ch)){
				concat(temp, ch);
				ch = strToken[++i];
			}
			ch = strToken[--i];
			results[++j].type = $INT;
			strcpy(results[j].attr, temp);
		}else{
			cout<<endl<<"ERROR:2 ";
			cout<<ch<<endl;
		}
		ch = strToken[++i];
	}
	cout<<"词法分析结束"<<endl;
	return j;
}

bool isLetter(char c){
	if(c>=65 && c<=93){
		return true;
	}else if(c>=97 && c<=122){
		return true;
	}else{
		return false;
	}
}
bool isDigit(char c){
	if(c>=48 && c<=57)return  true;
	return false;
}

void concat(char str[], char c){
	int length = strlen(str);
	str[length] = c;
}

int reserve(char str[]){
//#define $READ 1
//#define $WRITE 2
//#define $ASSIGN 3
//#define $BEGIN 4
//#define $END 5
//#define $TYPE_INT 6	// INT 数据类型
//#define $ID 7
//#define $INT 8	// 常数
//#define $LPAR 9	// (
//#define $RPAR 10	// ）
//#define $PLUS 11 // +
//#define $SUB 12	// -
//#define $COMMA 13 // 注释符号 --
//#define $SEMICOLON 14 // ;
	if(strcmp(str, "read")==0){
		return $READ;
	}else if(strcmp(str, "write")==0){
		return $WRITE;
	}else if(strcmp(str, "begin")==0){
		return $BEGIN;
	}else if(strcmp(str, "end")==0){
		return $END;
	}else if(strcmp(str, "INT")==0){
		return $INT;
	}else{
		return $ID;
	}
}